package put.cs.two.hied.netflix;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;

import javax.swing.plaf.SliderUI;

/**
 * @author Mateusz Chrominski
 * 
 */
public class ProbeReader {
    private Integer movieId = null;
    
    private boolean debug = false;

    private List<Integer> movieViewers = null;

    //movieId userIds
    Map<Integer, List<Integer>> ratings = new HashMap<Integer, List<Integer>>();
    
    //movieId userIds
    Map<Integer, List<Integer>> newProbe = new HashMap<Integer, List<Integer>>();
    
    //movieId userId
    List<Pair<Integer, Integer>> ratingsList = new ArrayList<Pair<Integer,Integer>>();
    
    //movieId userId
    //List<Pair<Integer, Integer>> newProbeList = new ArrayList<Pair<Integer,Integer>>();

    private final String filePath;

    public ProbeReader(String filePath) {
        this.filePath = filePath;
    }

    public void readFile() {
    	System.out.println("Reading from probe file...");
        try {
            BufferedReader in = new BufferedReader(new FileReader(filePath));
            String line;
            int lineIndex = 0;
            while ((line = in.readLine()) != null) {
            	if(lineIndex % 5000 == 0) {
            		System.out.println(" > processing line " + lineIndex);
            	}
                process(line);
                lineIndex++;
            }
            in.close();
        } catch (IOException e) {
        }
        System.out.println("Entries in ratings: " + ratings.size());
        
        if(debug) {
        	System.out.println("\nRatings list:");
        	for (Entry<Integer, List<Integer>> entry : ratings.entrySet()) {
        	    Integer key = entry.getKey();
        	    List<Integer> value = entry.getValue();
        	    System.out.print("Users for movie "+key+": ");
        	    for(Integer e : value) {
        	    	System.out.print(e + " ");
        	    }
        	    System.out.println();
        	}
        }

        try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {}
    }

    private void process(String line) {
        if (line.contains(":")) {
            movieId = Integer.parseInt(trim(line));
            movieViewers = new ArrayList<Integer>();
            ratings.put(movieId, movieViewers);
        } else {
            int userId = Integer.parseInt(line);
            movieViewers.add(userId);
            ratingsList.add(new Pair<Integer, Integer>(movieId, userId));
        }
    }
    
    public void setNewProbeSet(int percent) {
    	System.out.println("Set new probe set...");
    	if(ratings.size() > 0) {
    		int countOfNewProbe = (int) ((percent / 100.0) * ratingsList.size());
    		if(countOfNewProbe == 0)
    			countOfNewProbe = 2;
    		Random rand = new Random();
    		int probeCount = 0;
    		
    		System.out.println("10% entries from " + ratingsList.size() + " is " + countOfNewProbe);
    		try {
    			Thread.sleep(2000);
    		} catch (InterruptedException e) {}
    		
    		while(countOfNewProbe > 0) {
    			
				int min = 0;
				int max = ratingsList.size() - 1;
				int n = max - min + 1;
				int i = rand.nextInt() % n;
				if (i < 0) i = -i;
				int index = min + i;
				
				Pair<Integer, Integer> entry = ratingsList.get(index);
				//newProbeList.add(entry);
				//ratingsList.remove(index);
				if(newProbe.containsKey(entry.getFirst())) {
					newProbe.get(entry.getFirst()).add(entry.getSecond());
					probeCount++;
				} else {
					List<Integer> newUsersList = new ArrayList<Integer>();
					newUsersList.add(entry.getSecond());
					newProbe.put(entry.getFirst(), newUsersList);
					probeCount++;
				}
				ratings.get(entry.getFirst()).remove(entry.getSecond());
				if(ratings.get(entry.getFirst()).size() < 1) {
					ratings.remove(entry.getFirst());
				}
				ratingsList.remove(index);
				//Object[] values = ratings.keySet().toArray();
				//Object keyValue = values[index];
				//newProbe.put((Integer) keyValue, ratings.get(keyValue));
				//ratings.remove(keyValue);
				
    			countOfNewProbe--;
    			
    			if(countOfNewProbe % 2000 == 0) {
    				System.out.println(countOfNewProbe + " entries left...");
    			}
    		}
    		System.out.println("New probe set for " + probeCount + " entries");
        	try {
    			Thread.sleep(2000);
    		} catch (InterruptedException e) {}
    	}
    	
    	if(debug) {
	    	System.out.println("\nRatings list:");
	    	for (Entry<Integer, List<Integer>> entry : ratings.entrySet()) {
	    	    Integer key = entry.getKey();
	    	    List<Integer> value = entry.getValue();
	    	    System.out.print("Users for movie "+key+": ");
	    	    for(Integer e : value) {
	    	    	System.out.print(e + " ");
	    	    }
	    	    System.out.println();
	    	}
	
	    	System.out.println("\nProbe list:");
	    	for (Entry<Integer, List<Integer>> entry : newProbe.entrySet()) {
	    	    Integer key = entry.getKey();
	    	    List<Integer> value = entry.getValue();
	    	    System.out.print("Users for movie "+key+": ");
	    	    for(Integer e : value) {
	    	    	System.out.print(e + " ");
	    	    }
	    	    System.out.println();
	    	}
    	}
    }

    public static String trim(String line) {
        return line.substring(0, line.length() - 1);
    }

    public boolean hasEntry(TrainingSetEntry entry) {
        List<Integer> users = ratings.get(entry.getMovieId());
        if(users == null)
        	return false;
        else
        	return users.contains(entry.getUserId());
        //return users == null || users.contains(entry.getUserId());
    }
    
    public boolean hasEntryInProbe(TrainingSetEntry entry) {
        List<Integer> users = newProbe.get(entry.getMovieId());
        if(users == null)
        	return false;
        else
        	return users.contains(entry.getUserId());
        //return users == null || users.contains(entry.getUserId());
    }
    
    /*public boolean hasEntryInRatingList(TrainingSetEntry entry) {
    	Pair<Integer, Integer> entryPair = new Pair<Integer, Integer>(entry.getMovieId(), entry.getUserId());
    	return ratingsList.contains(entryPair);
    }
    
    public boolean hasEntryInNewProbeList(TrainingSetEntry entry) {
    	Pair<Integer, Integer> entryPair = new Pair<Integer, Integer>(entry.getMovieId(), entry.getUserId());
    	return newProbeList.contains(entryPair);
    }*/
}
